//
//  CannonView.m
//  CannonGame
//
//  Created by fly on 11/02/17.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "CannonView.h"

static const int CANNON_BASE_RADIUS = 25;		//加农炮炮身的半径
static const int CANNON_LENGTH=40;				//加农炮炮管长度

static const int CANNONBALL_RADIUS = 10;		//炮弹的半径
static const int CANNONBALL_VELOCITY= 600;		//炮弹的速度

static const int LINE_WIDTH = 10;				//目标和拦截器的宽度

static const int BLOCKER_DISTANCE = 200;		//拦截器到屏幕左边的距离
static const int BLOCKER_BEGINNING = 50;		//拦截器到屏幕顶端的距离
static const int BLOCKER_END = 200;				//拦截器底部到屏幕顶端的距离
static const int BLOCKER_VELOCITY = 300;		//拦截器的速度

static const int TARGET_VELOCITY=-100;			//目标的速度
static const int TARGET_DISTANCE=300;			//目标到屏幕左边的距离
static const int TARGET_BEGINNING=50;			//目标到屏幕顶端的距离
static const int TARGET_END = 400;				//目标底部到屏幕顶端的距离

static const int MISS_PENALTY = 2;				//失误时的减时
static const int HIT_HERWARD=3;					//击中时的加时

static const float TIME_INTERVAL = 0.025;		//定时器时间间隔


@implementation CannonView

//初始化视图
- (id)initWithCoder:(NSCoder *)aDecoder
{
	//判断父类是否被恰当地初始化
	if (self =[super initWithCoder:aDecoder])
	{
		//使加农炮初始指向水平方向
		barrelEnd = CGPointMake(CANNON_LENGTH,self.frame.size.height/2);
		
		//获取加农炮发射声音文件路径
		NSString *soundPath = [[NSBundle mainBundle] pathForResource:@"cannon_fire" ofType:@"wav"];
		
		//把路径转为一个URL
		NSURL *soundURL = [[NSURL alloc] initFileURLWithPath:soundPath];
		
		//以此URL初始化cannnonFirePlay
		cannonFireSound = [[AVAudioPlayer alloc] initWithContentsOfURL:soundURL error:nil];
		[soundURL release];
		
		
		//获取击中目标声音文件路径
		soundPath = [[NSBundle mainBundle] pathForResource:@"target_hit" ofType:@"wav"];
		
		//把路径转换位一个URL
		soundURL=[[NSURL alloc] initFileURLWithPath:soundPath];
		
		//以此URL初始化targetHitSound
		targetHitSound = [[AVAudioPlayer alloc] initWithContentsOfURL:soundURL error:nil];
		[soundURL release];
		
		
		//获取击中拦截器声音文件路径
		soundPath = [[NSBundle mainBundle] pathForResource:@"blocker_hit" ofType:@"wav"];
		
		//把路径转换为一个URL
		soundURL = [[NSURL alloc] initFileURLWithPath:soundPath];
		
		//以此URL初始化blockerHitSound
		blockerHitSound = [[AVAudioPlayer alloc] initWithContentsOfURL:soundURL error:nil];
		[soundURL release];
		
	}//end if
	return self;
}


//当nib文件加载结束时调用
- (void)awakeFromNib
{
	[self newGame];								//视图已经加载，那么开始一个新游戏
}


//重置所有地屏幕元素并开始一个新地游戏
- (void)newGame
{
	//基于定义地常量设置拦截器地初始位置
	blocker.start = CGPointMake(BLOCKER_DISTANCE, BLOCKER_BEGINNING);
	blocker.end   = CGPointMake(BLOCKER_DISTANCE, BLOCKER_END);
	
	//基于定义的常量设置目标的起始位置
	target.start = CGPointMake(TARGET_DISTANCE, TARGET_BEGINNING);
	target.end = CGPointMake(TARGET_DISTANCE, TARGET_END);
	
	//设置所有targetPieceHit为NO
	for (int i=0; i<TARGET_PIECES; i++) 
		targetPieceHit[i]=NO;					//未被击中
		
	targetPiecesHit = 0;						//没有目标片被击中
	
	blockerVelocity = BLOCKER_VELOCITY;		//设置拦截器初始速度
	targetVelocity = TARGET_VELOCITY;		//设置目标初始速度
	
	timeLeft = 30;							//以10秒启动倒数计时
	timerCount =0;							//计时器已经开始了0秒
	cannonballOnScreen=NO;					//加农炮炮弹不再屏幕上
	shotsFired = 0;							//设置射击数初始数值
	timeElapsed = 0;						//设置消逝时间
	
	//用给定时间间隔启动定时器
	timer = [NSTimer scheduledTimerWithTimeInterval:TIME_INTERVAL target:self selector:@selector(timerFired:) userInfo:nil repeats:YES];
	
	
}

//刷新屏幕所有元素
- (void)timerFired:(NSTimer *)theTimer
{
	//如果加农炮炮弹在屏幕上
	if(cannonballOnScreen)
	{
		//更新加农炮的位置
		cannonball.x += TIME_INTERVAL * cannonballVelocity.x;
		cannonball.y += TIME_INTERVAL * cannonballVelocity.y;
		
		//检查是否和拦截器发生碰撞
		if(cannonball.x > BLOCKER_DISTANCE - CANNONBALL_RADIUS *2  && cannonball.x < BLOCKER_DISTANCE + LINE_WIDTH/2 && 
		   cannonball.y + CANNONBALL_RADIUS*2 >blocker.start.y && cannonball.y <blocker.end.y)
		{
			cannonballVelocity.x *= -1;
			[blockerHitSound play];							//播放击中拦截器时的声音
			timeLeft -= MISS_PENALTY;
		}//end if
		
		//左右墙壁的碰撞检测
		else if(cannonball.x > self.frame.size.width || cannonball.x + CANNONBALL_RADIUS *2 <0 && cannonballVelocity.x <0)
			cannonballOnScreen=NO;							//使加农炮炮弹消逝
		
		//上下墙壁的碰撞检测
		else if(cannonball.y + CANNONBALL_RADIUS*2 <0 || cannonball.y >self.frame.size.height + CANNONBALL_RADIUS*2)
			cannonballOnScreen=NO;							//使加农炮炮弹消逝
		
		//检测是否击中目标
		else if(cannonball.x >TARGET_DISTANCE-CANNONBALL_RADIUS*2 && cannonball.x <TARGET_DISTANCE+LINE_WIDTH/2 &&
				cannonball.y+CANNONBALL_RADIUS*2 >target.start.y  && cannonball.y <target.end.y)
		{
			//计算每一片目标的长度
			float pieceLength=(TARGET_END-TARGET_BEGINNING)/TARGET_PIECES;
			
			//确定哪一个片段被击中(0代表最上面的那个)
			int section=(int)((cannonball.y-target.start.y)/pieceLength);
			
			//检查这个片段是否尚未被击中
			if(!targetPieceHit[section])
			{
				targetPieceHit[section]=YES;			//被击中
				cannonballOnScreen=NO;					//使加农炮炮弹消失
				timeLeft+= HIT_HERWARD;					//添加剩余时间
				[targetHitSound play];					//播放目标击中声音
				
				//如果所有的目标片段均被击中
				if(++targetPiecesHit==TARGET_PIECES)
				{
					NSString *message=[NSString stringWithFormat:@"Shots fired: %i¥n Time elapsed: %i seconds",shotsFired,timeElapsed];
					
					//显示游戏获胜提示框
					[self showAlertWithTitle:@"You Win!" message:message];
				}//end if
			}//end if
		}//end else
		
	}//end if
	
	
	//更新拦截器位置
	blocker.start.y += TIME_INTERVAL *blockerVelocity;
	blocker.end.y   += TIME_INTERVAL *blockerVelocity;
	
	//更新目标位置
	target.start.y += TIME_INTERVAL *targetVelocity;
	target.end.y   += TIME_INTERVAL *targetVelocity;
	
	//检测拦截器是否碰撞到上下墙壁
	if(blocker.start.y<0 || blocker.end.y>self.bounds.size.height)
		blockerVelocity*=-1;							//反转拦截器移动的方向
	
	//检测目标是否碰撞到上下墙壁
	if(target.start.y<0 || target.end.y >self.bounds.size.height)
		targetVelocity*=-1;								//反转目标移动的方向
	
	++timerCount;										//增加计时器事件数
	
	//如果过了1秒时间
	if(TIME_INTERVAL *timerCount >=1)
	{
		--timeLeft;										//剩余时间减1
		++timeElapsed;									//消逝时间加1
		timerCount=0;									//重置计时器事件数
	}//end if
	
	//如果计时剩余事件为0
	if(timeLeft<=0 && timerCount>0)
		//显示游戏结束警告框
		[self showAlertWithTitle:@"Game Over" message:nil];
	
	[self setNeedsDisplay];								//重新绘制整个界面显示
	
		
	
}

//使用给定标题和信息显示一个提示框
- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message
{
	[timer invalidate];					//停止并释放计时器
	timer=nil;							//设置计时器为空
	
	//创建这个游戏结束提示框
	UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:self cancelButtonTitle:@"New Game" otherButtonTitles:nil];
	[alert show];						//显示这个对话框
	[alert release];					//释放这个对话框
}


//当玩家触摸提示框中的新游戏按钮时调用
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
	[self newGame];						//开始一个新游戏
}

//绘制给定矩形内的界面显示
- (void)drawRect:(CGRect)rect
{
	//获取当前图形上下文
	CGContextRef context = UIGraphicsGetCurrentContext();
	
	//保存这个上下文，因为我们需要上下翻转它
	CGContextSaveGState(context);
	
	//向下移动该上下文坐标原点
	CGContextTranslateCTM(context, 0, self.bounds.size.height);
	CGContextScaleCTM(context, 1.0, -1.0);						//向上翻转图形上下文
	
	//以剩余时间来创建一个字符串
	NSString *str = [NSString stringWithFormat:@"Time remaining:%i seconds",timeLeft];
	
	//选择字体为16pt Helvetica
	CGContextSelectFont(context, "Helvetica", 16, kCGEncodingMacRoman);
	CGContextSetTextDrawingMode(context, kCGTextFill);			//设置绘制模式
	
	//设置文本颜色为黑色
	CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, 1.0);
	
	//转换str为一个C字符串并显示它
	CGContextShowTextAtPoint(context, 10.0, 10.0,  [str cStringUsingEncoding:[NSString defaultCStringEncoding]],str.length);
	CGContextRestoreGState(context);							//恢复上下文
	
	//如果炮弹在屏幕上
	if(cannonballOnScreen)
	{
		//创建矩形并在其中绘制炮弹
		CGRect	cannonballRect = CGRectMake(cannonball.x, cannonball.y, CANNONBALL_RADIUS*2, CANNONBALL_RADIUS*2);
		
		//加载这个炮弹图片
		UIImage *image=[UIImage imageNamed:@"cannonball80.png"];
		
		//绘制图片到矩形中
		CGContextDrawImage(context, cannonballRect, image.CGImage);
	}//end if
	
	
	//绘制加农炮炮管
	//移动加农炮底座到视图中间位置
	CGContextMoveToPoint(context, 0, self.frame.size.height/2);
	
	//添加一根到加农炮炮管终端的线条
	CGContextAddLineToPoint(context, barrelEnd.x, barrelEnd.y);
	CGContextSetLineWidth(context, 20);							//设置线条粗细
	CGContextSetRGBStrokeColor(context, 0.0, 0.0, 0.0, 1.0);	//黑色
	CGContextStrokePath(context);								//绘制线条
	
	//为加农炮炮底座创建矩形
	CGRect cannonBase = CGRectMake(0, self.frame.size.height/2-CANNON_BASE_RADIUS,CANNON_BASE_RADIUS ,CANNON_BASE_RADIUS*2 );
	
	//加载加农炮底座图片
	UIImage *baseImage=[UIImage imageNamed:@"cannon_base.png"];
	
	//把加农炮底座图片绘制到矩形中
	CGContextDrawImage(context, cannonBase, baseImage.CGImage);
	
	//在拦截器两个端点之间添加一根线条
	CGContextMoveToPoint(context, blocker.start.x, blocker.start.y);
	CGContextAddLineToPoint(context, blocker.end.x, blocker.end.y);
	CGContextSetLineWidth(context, LINE_WIDTH);					//设置线条
	
	CGContextStrokePath(context);								//绘制线条
	
	//计算目标每个分段的长度
	float pieceLength=(TARGET_END - TARGET_BEGINNING)/TARGET_PIECES;
	
	//移到目标起点
	CGContextMoveToPoint(context, target.start.x, target.start.y);
	
	//绘制每个目标分段
	for (int i=0; i<=TARGET_PIECES; i++) 
	{
		//相邻分段以黄／蓝两色区分开
		if(i%2==0)
			CGContextSetRGBStrokeColor(context, 1, 1, 0, 1);
		else
			CGContextSetRGBStrokeColor(context, 0, 0, 0.5, 1);
		
		//移到下一个分段的端点
		CGContextMoveToPoint(context, target.end.x, target.start.y+pieceLength*(i-1));
		
		//如果这个分段还没有被击中
		if(!targetPieceHit[i-1])
		{
			//为该分段添加一条线
			CGContextAddLineToPoint(context, target.end.x, target.start.y+pieceLength*i);
			CGContextStrokePath(context);						//绘制分段
		}
	}//end for
	
}//end method drawRect:


//- (id)initWithFrame:(CGRect)frame {
//    if ((self = [super initWithFrame:frame])) {
//        // Initialization code
//    }
//    return self;
//}

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
}
*/

- (void)dealloc {
    [super dealloc];
}


@end
